﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
using System.IO;

namespace Sofire.DataComm.Remoting.Server.Settings
{
    /// <summary>
    /// 服务配置信息。
    /// </summary>
    public partial class ServiceSetting : SettingBase
    {
        /// <summary>
        /// 主机配置信息。
        /// </summary>
        internal HostSetting _Host;
        /// <summary>
        /// 表示主机配置信息。
        /// </summary>
        public HostSetting Host
        {
            get
            {
                return this._Host;
            }
        }

        private Type _Contract;
        /// <summary>
        /// 表示服务的契约类型。
        /// </summary>
        public Type Contract
        {
            get
            {
                return this._Contract;
            }
            internal set
            {
                if(this._Contract != value)
                {
                    this._Contract = value;
                    this.CheckServiceType();
                    this.RegisterContract();
                }
            }
        }

        private Type _Type;
        /// <summary>
        /// 表示服务的类型。
        /// </summary>
        public Type Type
        {
            get
            {
                return this._Type;
            }
            internal set
            {
                if(this._Type != value)
                {
                    this._Type = value;
                    this.CheckServiceType();
                }
            }
        }

        private object _Instance;
        /// <summary>
        /// 表示服务的实例。
        /// </summary>
        public object Instance
        {
            get
            {
                return this._Instance;
            }
            internal set
            {
                this._Instance = value;
            }
        }

        private string _FullName;
        /// <summary>
        /// 获取服务的全称。
        /// </summary>
        public string FullName
        {
            get
            {
                if(this._Host == null) return string.Empty;
                if(this._FullName == null)
                {
                    this._FullName = this._Host.Name + "/" + this.Name + ".v";
                }
                return this._FullName;
            }
        }

        private int _Version = 1;
        /// <summary>
        /// 获取服务版本，默认为“1”。
        /// </summary>
        public int Version
        {
            get
            {
                return this._Version;
            }
        }

        private int _SessionExpiration = 20;
        /// <summary>
        /// 获取会话的最大超时时间。小于 0 则表示无超时，等于 0 表示不启用。大于 0 则表示指定的超时秒数。默认为“20”秒。
        /// </summary>
        public int SessionExpiration
        {
            get
            {
                return this._SessionExpiration;
            }
        }

        private readonly static System.Web.HttpRuntime httpRuntime = new System.Web.HttpRuntime();
        /// <summary>
        /// 全局缓存机制。
        /// </summary>
        public readonly static System.Web.Caching.Cache Cache = System.Web.HttpRuntime.Cache;
        static void SessionExpirationCallBack(string key, object value, System.Web.Caching.CacheItemRemovedReason reason)
        {
            var entry = (value as SessionEntry);
            if(entry != null) entry.IsExpired = true;
        }

        /// <summary>
        /// 获取指定会话编号的会话实例。
        /// </summary>
        /// <param name="sessionID">会话编号。</param>
        /// <returns>返回一个已存在或新建立的会话实例。</returns>
        public SessionEntry this[string sessionID]
        {
            get
            {
                if(this._SessionExpiration < 0) return null;
                //- 在正确的逻辑中，不需要进行线程锁
                var value = Cache.Get(sessionID);
                if(value == null)
                {
                    value = new SessionEntry();
                    if(this._SessionExpiration == 0)
                    {
                        Cache.Add(sessionID, value, null
                            , DateTime.MaxValue
                            , System.Web.Caching.Cache.NoSlidingExpiration
                            , System.Web.Caching.CacheItemPriority.Default, SessionExpirationCallBack);
                    }
                    else
                    {
                        Cache.Add(sessionID, value, null
                            , System.Web.Caching.Cache.NoAbsoluteExpiration
                            , TimeSpan.FromMinutes(this._SessionExpiration)
                            , System.Web.Caching.CacheItemPriority.Default, SessionExpirationCallBack);
                    }
                }
                return value as SessionEntry;
            }
        }

        /// <summary>
        /// 检查指定的会话编号是否存在。
        /// </summary>
        /// <param name="sessionID">会话编号。</param>
        /// <returns>如果该会话已存在则返回 true，否则返回 false。</returns>
        public bool SessionExists(string sessionID)
        {
            return Cache.Get(sessionID) != null;
        }

        private InstanceRegisterMode _InstanceMode = InstanceRegisterMode.Default;
        /// <summary>
        /// 表示服务实例的注册模式。
        /// </summary>
        public InstanceRegisterMode InstanceMode
        {
            get
            {
                return this._InstanceMode;
            }
            internal set
            {
                this._InstanceMode = value;
            }
        }

        /// <summary>
        /// 表示在实例创建时发生。如果注册了此事件，客户端每一次调用都会触发此事件。注意，<see cref="Sofire.DataComm.Remoting.Server.Settings.ServiceSetting.InstanceMode"/> 必须为 <see cref="Sofire.DataComm.Remoting.Server.Settings.InstanceRegisterMode.Custom"/> 时才有效。
        /// </summary>
        public event InstanceCreatingEventHandler InstanceCreating;

        internal ServiceSetting() { }

        internal override void Initialization(XmlElement element)
        {
            base.Initialization(element);

            var value = element.TryGetAttribute(TypeAttribute);
            if(string.IsNullOrEmpty(value)) throw this.CreateException(ServerErrorCode.EmptyAttribute, TypeAttribute);
            this._Type = this.ConvertToType(value);

            value = element.TryGetAttribute(ContractAttribute);
            if(string.IsNullOrEmpty(value)) throw this.CreateException(ServerErrorCode.EmptyAttribute, ContractAttribute);
            this.Contract = this.ConvertToType(value);


            value = element.TryGetAttribute(InstanceModeAttribute);

            if(!string.IsNullOrEmpty(value)) this._InstanceMode = (InstanceRegisterMode)Enum.Parse(typeof(InstanceRegisterMode), value, true);

            if(this._InstanceMode == InstanceRegisterMode.Call && this._Type.GetConstructor(new Type[0]) == null)
            {
                throw this.CreateException(ServerErrorCode.InvalidConstructorWithCallMode, InstanceModeAttribute, this._Type.FullName);
            }

            value = element.TryGetAttribute(SessionExpirationAttribute);
            int iValue;
            if(!string.IsNullOrEmpty(value))
            {
                if(int.TryParse(value, out iValue)) this._SessionExpiration = iValue;
                else throw this.CreateException(ServerErrorCode.SessionExpiration, SessionExpirationAttribute, value);
            }

            value = element.TryGetAttribute(VersionAttribute);
            if(!string.IsNullOrEmpty(value))
            {
                if(int.TryParse(value, out iValue)) this._Version = iValue;
                else throw this.CreateException(ServerErrorCode.VersionExpiration, VersionAttribute, value);
            }

        }

        private void CheckServiceType()
        {//- 检查服务类型是否实现了契约类型。如果契约是一个接口，并且服务实现了这个契约，则不会报错。

            if(this._Type == null || this._Contract == null) return;
            if(!this._Contract.IsInterface || !this._Contract.IsAssignableFrom(this._Type))
                throw this.CreateException(ServerErrorCode.InvalidContract, ContractAttribute, this._Contract.FullName + "\r\n" + this._Type.FullName);
        }

        private Type ConvertToType(string value)
        {//- 将给定的字符串转换为 System.Type

            var type = System.Type.GetType(value, false);
            if(type != null) return type;

            foreach(var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = assembly.GetType(value, false);
                if(type != null) return type;
            }

            throw this.CreateException(ServerErrorCode.InvalidType, value);
        }

    }

    //- 对 IServer 开放的接口
    public partial class ServiceSetting
    {
        private object NewInstance(IServer server)
        {//- 创建一个新的服务实例。

            if(this._Instance != null) return this._Instance;

            return Activator.CreateInstance(this._Type, true);
        }

        private readonly object serverSyncObject = new object();
        private Dictionary<IServer, object> serverInstances = new Dictionary<IServer, object>(); //- 服务器对应的服务实例（服务实例）。

        private readonly static object globalSyncObject = new object();
        private static readonly Dictionary<Type, object> globalInstances = new Dictionary<Type, object>(); //- 类型对应的服务实例（全局实例）。

        private Dictionary<int, ContractMethodInfo> _ContractMethods;

        private byte[] _methodSyncInfosBytes;

        /// <summary>
        /// 根据当前服务配置，创建或返回一个服务实例。
        /// </summary>
        /// <param name="server">服务器。</param>
        /// <returns>返回一个服务实例。</returns>
        internal object FindInstance(IServer server)
        {
            switch(this._InstanceMode)
            {
                case InstanceRegisterMode.Default:
                    {//- 默认的注册模式，在注册 InstanceCreating 事件后转到 Custom 的处理方式。否则就当做服务配置级的实例。
                        if(this.InstanceCreating != null) goto case InstanceRegisterMode.Custom;
                        goto default;
                    }
                case InstanceRegisterMode.Global:
                    {//- 全局模式。静态字段 globalObjects 存储了根据类型作为 key 的字典。
                        object o;
                        lock(globalSyncObject)
                        {
                            if(!globalInstances.TryGetValue(this._Type, out o))
                            {
                                o = this.NewInstance(server);
                                globalInstances.Add(this._Type, o);
                            }
                        }
                        return o;
                    }
                case InstanceRegisterMode.Call: return Activator.CreateInstance(this._Type, true);

                case InstanceRegisterMode.Custom:
                    {//- 自定义模式，事件为空就异常，
                        if(this.InstanceCreating == null) throw this.CreateException(ServerErrorCode.UnregisteredInstanceCreating);

                        var e = new InstanceCreatingEventArgs(server);
                        this.InstanceCreating(this, e);
                        if(e.Instance == null) throw this.CreateException(ServerErrorCode.NullInstanceCreating);

                        return e.Instance;
                    }
                default:
                    {
                        object o;
                        lock(serverSyncObject)
                        {
                            if(!serverInstances.TryGetValue(server, out o))
                            {
                                o = this.NewInstance(server);
                                serverInstances.Add(server, o);
                            }
                        }
                        return o;
                    }
            }

        }

        /// <summary>
        /// 获取契约的所有公共方法。
        /// </summary>
        internal Dictionary<int, ContractMethodInfo> ContractMethods
        {
            get { return this._ContractMethods; }
        }

        /// <summary>
        /// 获取提供给客户端的开放接口序列化后的字节。
        /// </summary>
        internal byte[] MethodSyncInfosBytes
        {
            get
            {
                return this._methodSyncInfosBytes;
            }
        }

        /// <summary>
        /// 清空服务级的所有实例。
        /// </summary>
        internal void ResetInstances()
        {
            lock(serverSyncObject)
            {
                serverInstances.Clear();
            }
        }

        /// <summary>
        /// 清空全局级的所有实例。
        /// </summary>
        internal static void ResetGlobalInstances()
        {
            lock(globalSyncObject)
            {
                globalInstances.Clear();
            }
        }

        private void RegisterContract()
        {//- 注册一个契约

            var interfaces = this._Contract.GetInterfaces();

            var currentMethodIdent = 0;

            _ContractMethods = new Dictionary<int, ContractMethodInfo>();

            RegisterInterface(this._Contract, ref currentMethodIdent);

            foreach(var interfaceType in interfaces)
            {
                RegisterInterface(interfaceType, ref currentMethodIdent);
            }

            var syncInfos = new List<MethodSyncInfo>();

            Type t;
            MethodInfo method;
            ParameterInfo[] parameters;
            string[] parameterTypes;
            foreach(var kvp in this._ContractMethods)
            {
                method = kvp.Value.Method;
                parameters = method.GetParameters();
                parameterTypes = new string[parameters.Length];
                for(var i = 0 ; i < parameters.Length ; i++)
                {
                    t = parameters[i].ParameterType;
                    //- 简单类型字符串，不含版本和区域 TypeFullName, AssemblySimpleName
                    //- 减少序列化 RuntimeType 的字节
                    parameterTypes[i] = t.FullName + ", " + t.Assembly.GetName().Name;
                }
                syncInfos.Add(new MethodSyncInfo(kvp.Key, method.Name, parameterTypes));
            }

            this._methodSyncInfosBytes = RemotingShare.Formatter.FastWriteBytes(syncInfos);

        }

        private void RegisterInterface(Type interfaceType, ref int currentMethodIdent)
        {//- 给定一个接口类型

            //- GetMethods 包含以下四种 c# 特性
            //- 1、普通方法
            //- 2、this 索引器
            //- 3、属性
            //- 4、事件

            var methodInfos = interfaceType.GetMethods();
            foreach(var mi in methodInfos)
            {
                RegisterMethod(mi, ref currentMethodIdent);
            }

            //foreach(var pi in interfaceType.GetProperties())
            //{
            //    if(pi.CanWrite) RegisterMethod(pi.GetSetMethod(), ref currentMethodIdent);
            //    if(pi.CanRead) RegisterMethod(pi.GetGetMethod(), ref currentMethodIdent);
            //}
        }

        private void RegisterMethod(MethodInfo method, ref int currentMethodIdent)
        {//- 注册一个方法

            if(method == null) return;

            var parameterInfos = method.GetParameters();
            var isByRef = new bool[parameterInfos.Length];

            for(int i = 0 ; i < isByRef.Length ; i++) isByRef[i] = parameterInfos[i].ParameterType.IsByRef;

            this._ContractMethods.Add(currentMethodIdent, new ContractMethodInfo(currentMethodIdent, method, isByRef, this._Type));
            currentMethodIdent++;
        }

        internal override SettingException CreateException(ServerErrorCode errorCode, string propertyName, string propertyValue)
        {
            return new SettingException(errorCode, propertyName, propertyValue)
            {
                _Application = this._Host._Application,
                _Host = this._Host,
                _Service = this,
            };
        }

    }
}
